#include <gl/glew.h>
#include <gl/freeglut.h>
#include <iostream>
#include <string>
#include <math.h>
#include <ctime>
#include <windows.h>

#include "Game.h"
#include "LogginListener.h"
#include "Event.h"
#include "Mapa.h"
#include "EscenaJugando.h"
#include "LuaFunctions.h"
#include "CorutinaCamara.h"
#include "FullScreenActor.h"

//includes temporales para pruebas



#define COMPILE_TIMESTAMP __DATE__ " " __TIME__
#define FILE_INFO __FILE__, __LINE__

using namespace std;

Game *g = NULL;//unica variable Global

Game::Game(int anchoPantalla, int altoPantalla) {

	log 		= NULL;
	fps 		= NULL;
	eventos 	= NULL;
	pilaEscenas	= NULL;
	recursos 	= NULL;
	//fuente 		= NULL;

	rutinas		= NULL;
	trmanager	= NULL;
	audioSystem = NULL;


	//inicializamos el audio
	FMOD::System_Create(&audioSystem);
	audioSystem->init(32,FMOD_INIT_NORMAL,0);

	ultimaID = 0;
	gameTime = 0.f;
	//creacion en memoria
	log 		= new EngineLogin("logs/Log.xml");
	fps 		= new FrameRate(60.f);
	eventos 	= new EventManager();
	pilaEscenas	= new SceneManager();
	recursos 	= new ResourceManager();
	//fuente 		= new FTGLTextureFont("data/fuentes/times.ttf");
	camara 		= new Camara;

	rutinas		= new CorutineManager;
	trmanager	= new TransitionManager;



	//nada que se subscriba a eventos puede llamar a metodos getters, no se por que
	
	L = lua_open();
	luaL_openlibs(L);
	LuaFunctions::registrarFunciones(L);

	//fuente->FaceSize(16);
	
	//Log
	
	log->add_tag_tree("Proyecto");
	log->add_tag("Nombre","Unknown");
	log->add_tag("Fichero", __FILE__);
	log->add_tag("FechaCompilacion", COMPILE_TIMESTAMP);
	log->add_tag_tree("Mensajes");
	log->add_tag("mensaje","Iniciando engine.");

	srand((unsigned)time(0)); 

	this->altoPantalla = altoPantalla;
	this->anchoPantalla = anchoPantalla;	

	memset(teclas,false,256);

	eventos->addListener(CARGANDO_MAPA,trmanager);
	eventos->addListener(CARGANDO_ESCENA,pilaEscenas);
	

	eventos->enviarEvento(new Event(CARGANDO_ESCENA,new eventoCargarEscena(new EscenaJugando())));

	r = g = b = 1.f;

	
}
/**
	Inicializa los valores de OPENGL.
**/
float tal = 0.f;
void Game::oglInit() {
	//addActor(new FullScreenActor(getNewID(),string("test.png")));

	glDisable(GL_DEPTH_TEST);
	glClearColor(0.0f,0.0f,0.0f,1.f);
	glEnable(GL_TEXTURE_2D);
	glEnable(GL_BLEND);
	glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	
		
	eventos->enviarEventos();


	
	
}


void Game::render() {
	pilaEscenas->render();	

}


void Game::update(float velocidadActual) {

	hash_map<ID,Actor*>::iterator it;
	
	for (it = actores.begin(); it != actores.end();)
		if (it->second->isMarcadoEliminacion()){
			eventos->enviarEvento(new Event(ACTOR_BORRADO));
			delete it->second;
			actores.erase(it);
			break;
		}else{
			it->second->update(velocidadActual);
			++it;
		}
		

	eventos->enviarEventos();

	pilaEscenas->update(velocidadActual);
	audioSystem->update();
	rutinas->update(velocidadActual);
	trmanager->update(gameTime);
	recursos->update(gameTime);
	gameTime = glutGet(GLUT_ELAPSED_TIME);
}



void Game::loop() {

	if (!pilaEscenas->quedanEscenas())
		cerrar();
	
	update(fps->getSpeed());
	glutPostRedisplay();

	//control de FPS
	fps->SetSpeedFactor();
	fps->update();
	if ((loops%100) == 0)
		log->add_tag("FPS",fps->getFPS());
	++loops;
}
void Game::reshape(int w, int h) {

	glViewport(0, 0, w, h);
	glMatrixMode( GL_PROJECTION);
	glLoadIdentity();
	glMatrixMode (GL_PROJECTION);
		glLoadIdentity ();
		glOrtho (0, w, h, 0, 0, 1);
		glDisable(GL_DEPTH_TEST);
		glMatrixMode (GL_MODELVIEW);
		glLoadIdentity();
	if (h == 0) 
		gluPerspective(80, (float) w, 0.5f, 5000.0);
	else
		gluPerspective(80, (float) w / (float) h, 0.5f, 5000.0);
	glMatrixMode( GL_MODELVIEW);
	glLoadIdentity();
	this->altoPantalla = h;
	this->anchoPantalla = w;
	eventos->enviarEvento(new Event(RESOLUCION_CAMBIADA,new eventoResolucion(w,h)));

	
}
void Game::cerrar(void){

	log->add_tag("mensaje","Finalizacion del engine.");
	log->close_tag_tree();
	delete log;
	delete fps;
	//delete eventos;	
	delete recursos;
	//delete fuente;
	delete camara;
	delete trmanager;
	//delete pilaEscenas;
	exit(0);
	}


Game::~Game() {
	cerrar();
	}


// =======================
// Entrada de usuario
// =======================
void Game::flechas(int a_keys, int x, int y) {

	}


void Game::teclado(unsigned char key, int x, int y, bool keydown) {
	void *data = new eventoTeclado(x,y,key);
	eventos->enviarEvento(new Event(keydown ? TECLA_PULSADA : TECLA_SOLTADA, data));
	teclas[key] = keydown;
	}

void Game::raton(int x, int y) {
	eventos->enviarEvento(new Event(RATON_MOVIDO, new eventoMovimientoRaton(x,y)),false);
	}

void Game::botonRaton( int boton, int estado, int x, int y )
	{
	eventos->enviarEvento(new Event(GLUT_DOWN == estado ? RATON_BOTON_PULSADO : RATON_BOTON_SOLTADO, new eventoPulsacionRaton(boton,x,y)));
	}

void Game::addActor( Actor *actor )
	{
		actores[actor->getID()] = actor;
		eventos->enviarEvento(new Event(NUEVO_ACTOR,new eventoNuevoActor(actor)));
	}